#include "camdrv.h"
#include "camplus.h"
#include <stdio.h>
#include <stdlib.h>


#define DIGITALZOOM_MAX 4

CameraDriver g_CameraDriver;


void InitCamFormat(CamFormat &f)
{
    f.m_imode = PHOTO_MODE;
    f.m_iPhotoResolution = 1;//320*240
    f.m_iVideoResolution = 2;//276*144
    f.m_iPhotoZoom = 1;//Must be supported
    f.m_iBrightness = 50;//OK
    f.m_iWhiteBalance = CAMERA_WB_AUTO;//OK
    f.m_iColorMode = CAMERA_CM_AUTO;//OK
    f.m_iSceneMode = CAMERA_SM_AUTO;//Must be supported
    f.m_iContinuousSnaps = 1;//Must be supported
    f.m_iFrameRate = 0;//dummy
    f.m_iContrast = 0;//dummy
    f.m_iSharpness = 0;//dummy
    f.m_iDirection = 0;//dummy
    f.m_iFlash = 0;//dummy
    f.m_iISO = 0;//dummy
    f.m_iExposureCompensation = 0;//dummy
}


ECode CameraDriver::CamDrv_Initialize()
{
    ECode ec;
    if(nu_CameraInit()){
        DRV_EXPRESSION(ERRORLEVEL,
            kprintf("CamDrv_Initialize nu_CameraInit failed\n"));
        return E_INVALID_OPERATION;
    }
    kprintf("nu_CameraInit ok\n");

    InitCamFormat(m_Format);

    //Default in sanp preview
    ec = m_Preview.Initialize(CAM_MODE_PREVIEW);
    if(FAILED(ec)){
        DRV_EXPRESSION(ERRORLEVEL,
            kprintf("CamDrv_Initialize m_Preview.Initialize failed\n"));
        goto ERR;
    }

    m_pVideo = new CCamVideo();
    if(NULL == m_pVideo){
        kprintf("Not enough memery CCamVideo\n");
        ec = E_OUT_OF_MEMORY;
        goto ERR;
    }

    ec = m_pVideo->Initialize(CAM_MODE_CAPDISP);
    if(FAILED(ec)){
        kprintf("Error:camera driver CamDrv_Initialize failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        goto ERR;
    }

    m_pSnapshot = new CCamSnapshot();
    if(NULL == m_pSnapshot){
        kprintf("Not enough memery CCamSnapshot\n");
        ec = E_OUT_OF_MEMORY;
        goto ERR;
    }

    ec = m_pSnapshot->Initialize();
    if(FAILED(ec)){
        kprintf("Error:camera driver CamDrv_Initialize failed! \
        file:%s. line:%d. \n",
        __FILE__, __LINE__);
        goto ERR;
    }

    return NOERROR;

ERR:
	CamDrv_Quit();
    return ec;

}

void CameraDriver::CamDrv_Quit()
{
    nu_CameraDeinit();
    m_Preview.Destroy();
    if(NULL != m_pVideo){
        m_pVideo->Destroy();
        delete m_pVideo;
        m_pVideo = NULL;
    }
    if(NULL != m_pSnapshot){
        m_pSnapshot->Destroy();
        delete m_pSnapshot;
        m_pSnapshot = NULL;
    }
}

//Set param
ECode  CameraDriver::CamDrv_SetCamMode(int iMode)
{
    ECode ec;

    if (PHOTO_MODE == iMode) {//photo mode
        m_Preview.Destroy();
        ec = m_Preview.Initialize(CAM_MODE_PREVIEW);
        if(FAILED(ec)){
            DRV_EXPRESSION(ERRORLEVEL,
                kprintf("CamDrv_SetCamMode m_Preview.Initialize failed\n"));
            return ec;
        }
        m_Format.m_imode = PHOTO_MODE;
		m_pVideo->Destroy();
    } else {//video mode
        m_Preview.Destroy();
        ec = m_Preview.Initialize(CAM_MODE_VIDEO_PREVIEW);
        if(FAILED(ec)){
            DRV_EXPRESSION(ERRORLEVEL,
                kprintf("CamDrv_SetCamMode m_Preview.Initialize failed\n"));
            return ec;
        }
        m_Format.m_imode = VIDEO_MODE;
		m_pSnapshot->Destroy();
    }

    return NOERROR;
}

ECode  CameraDriver::CamDrv_SetAppFormat(unsigned int nID, int wParam, int lParam)
{
    ECode ec = NOERROR;
    switch (nID) {
    case CAMERA_FORMAT_PHOTO_RESOLUTION:
        if (wParam > 5) wParam = 5;//1600*1200
        if (wParam < 0) wParam = 0;//160*120
        m_Format.m_iPhotoResolution = wParam;
        break;
    case CAMERA_FORMAT_VIDEO_RESOLUTION:
        if (wParam > 3) wParam = 3;//320*240
        if (wParam < 0) wParam = 0;//88 x 72
        m_Format.m_iVideoResolution = wParam;
        break;
    case CAMERA_FORMAT_ZOOM://Just used in photo mode
        if(PHOTO_MODE == m_Format.m_imode){
            int zoom = wParam / lParam;
            if (zoom < 1 || zoom > DIGITALZOOM_MAX){
                zoom = 1;
            }
            m_Format.m_iPhotoZoom = zoom;
            nu_CameraSetZoom(m_Format.m_iPhotoZoom);
        } else {
            ec = E_INVALID_OPERATION;
        }
        break;
    case CAMERA_FORMAT_BRIGHTNESS:
        if (wParam > 255) wParam = 255;
        if (wParam < 0) wParam = 0;
        m_Format.m_iBrightness = wParam;
        nu_CameraSetBrightness(m_Format.m_iBrightness);
        break;
    case CAMERA_FORMAT_WHITEBALANCE:
        if (wParam > 5) wParam = 5;
        if (wParam < 0) wParam = 0;
        m_Format.m_iWhiteBalance = wParam;
        nu_CameraSetWhiteBalance(m_Format.m_iWhiteBalance);
        break;
    case CAMERA_FORMAT_COLORMODE:
        m_Format.m_iColorMode = wParam;
        nu_CameraSetColoreffects(m_Format.m_iColorMode);
        break;
    case CAMERA_FORMAT_SCENEMODE:
        m_Format.m_iSceneMode = wParam;
        nu_CameraSetScenemode(m_Format.m_iSceneMode);
        break;
    case CAMERA_FORMAT_CONTINUOUS_SNAP:
        if (wParam > 3) wParam = 3;
        if (wParam < 1) wParam = 1;
        m_Format.m_iContinuousSnaps = wParam;
        break;
    case CAMERA_FORMAT_CONTRAST:
        m_Format.m_iContrast = wParam;
        nu_CameraSetContrast(m_Format.m_iContrast);
        break;
    case CAMERA_FORMAT_SHARPNESS:
        m_Format.m_iSharpness = wParam;
        break;
    case CAMERA_FORMAT_FLASH:
        m_Format.m_iFlash = wParam;
        break;
    case CAMERA_FORMAT_EXPOSURE_COMPENSATION:
        m_Format.m_iExposureCompensation = wParam;
        break;
    case CAMERA_FORMAT_FRAMERATE:
        m_Format.m_iFrameRate = wParam;
        break;
    case CAMERA_FORMAT_DIRECTION:
        m_Format.m_iDirection = wParam;
        break;
    case CAMERA_FORMAT_ISO:
        m_Format.m_iISO = wParam;
        break;
    default:
        ec = E_NOT_IMPLEMENTED;
        break;
    }
    return ec;
}


ECode  CameraDriver::CamDrv_GetAppFormat(unsigned int nID, int *pwParam, int *plParam)
{
    ECode ec = NOERROR;
    switch (nID) {
    //BUGBUG:The AppResolution width > Height, different from internal
    case CAMERA_FORMAT_PHOTO_GETSIZE:
        ResolutionOfSnapshot(m_Format.m_iPhotoResolution,
          plParam,
          pwParam);
        break;
    //BUGBUG:The AppResolution width > Height, different from internal
    case CAMERA_FORMAT_VIDEO_GETSIZE:
        ResolutionOfVideo(m_Format.m_iVideoResolution,
                  plParam,
                  pwParam);
        break;
    case CAMERA_FORMAT_PHOTO_RESOLUTION:
        *pwParam = m_Format.m_iPhotoResolution;
        break;
    case CAMERA_FORMAT_VIDEO_RESOLUTION:
        *pwParam = m_Format.m_iVideoResolution;
        break;
    case CAMERA_FORMAT_ZOOM:
        if(0 == m_Format.m_imode){
            *pwParam = m_Format.m_iPhotoZoom;
        } else {
            *pwParam = 1;
        }
        break;
    case CAMERA_FORMAT_BRIGHTNESS:
        *pwParam = m_Format.m_iBrightness;
        break;
    case CAMERA_FORMAT_WHITEBALANCE:
        *pwParam = m_Format.m_iWhiteBalance;
        break;
    case CAMERA_FORMAT_COLORMODE:
        *pwParam = m_Format.m_iColorMode;
        break;
    case CAMERA_FORMAT_SCENEMODE:
        *pwParam = m_Format.m_iSceneMode;
        break;
    case CAMERA_FORMAT_CONTINUOUS_SNAP:
        *pwParam = m_Format.m_iContinuousSnaps;
        break;
    case CAMERA_FORMAT_PHOTO_GETFRAMESIZE:{
        int iWidth;
        int iHeight;
        ResolutionOfSnapshot(m_Format.m_iPhotoResolution,
                  &iWidth,
                  &iHeight);
        *pwParam = iWidth
                 * iHeight
                 * CAMERA_DATA_BYTES;
    }
        break;
    case CAMERA_FORMAT_CONTRAST:
        *pwParam = m_Format.m_iContrast;
        break;
    case CAMERA_FORMAT_SHARPNESS:
        *pwParam = m_Format.m_iSharpness;
        break;
    case CAMERA_FORMAT_FLASH:
        *pwParam = m_Format.m_iFlash;
        break;
    case CAMERA_FORMAT_EXPOSURE_COMPENSATION:
        *pwParam = m_Format.m_iExposureCompensation;
        break;
    case CAMERA_FORMAT_FRAMERATE:
        *pwParam = m_Format.m_iFrameRate;
        break;
    case CAMERA_FORMAT_DIRECTION:
        *pwParam = m_Format.m_iDirection;
        break;
    case CAMERA_FORMAT_ISO:
        *pwParam = m_Format.m_iISO;
        break;
    default:
        ec = E_NOT_IMPLEMENTED;
        break;
    }
    return ec;
}

//Preview
ECode  CameraDriver::CamDrv_BeginPreview(IEvent ** ppOutEvent)
{
    int iWidth;
    int iHeight;
    if(VIDEO_MODE == m_Format.m_imode) {
        ResolutionOfVideo(m_Format.m_iVideoResolution,
                  &iWidth,
                  &iHeight);
    } else {
        if(m_Format.m_iPhotoResolution < 2) {
            ResolutionOfSnapshot(m_Format.m_iPhotoResolution,
                      &iWidth,
                      &iHeight);
        } else {
            iWidth = PREVIEW_WIDTH;
            iHeight = PREVIEW_HEIGHT;
        }
    }
    return m_Preview.Start(iWidth, iHeight, ppOutEvent);
}

ECode  CameraDriver::CamDrv_StopPreview()
{
    return m_Preview.Stop();
}

ECode  CameraDriver::CamDrv_GetPreviewFrame(Camera_ImageFrame* pFrame)
{
    return m_Preview.GetFrame(pFrame);
}

//Snap
ECode  CameraDriver::CamDrv_GetSnapshotFrames(Camera_Photo *pPhoto)
{
    if(PHOTO_MODE == m_Format.m_imode){
        int iWidth;
        int iHeight;
        ResolutionOfSnapshot(m_Format.m_iPhotoResolution,
                  &iWidth,
                  &iHeight);
        return m_pSnapshot->GetSnapshotFrames(iWidth, iHeight, pPhoto);
    }
    return E_ACCESS_DENIED;
}

void CameraDriver::CamDrv_ReleaseFrames()
{
    if(PHOTO_MODE == m_Format.m_imode){
        m_pSnapshot->ReleaseFrames();
    }
}

//Video
ECode  CameraDriver::CamDrv_BeginVideoRecord(IEvent ** ppOutEvent)
{
    if(VIDEO_MODE == m_Format.m_imode){
        int iWidth;
        int iHeight;
        ResolutionOfVideo(m_Format.m_iVideoResolution,
                  &iWidth,
                  &iHeight);
        return m_pVideo->Start(iWidth, iHeight, ppOutEvent);
    }
    return E_ACCESS_DENIED;
}

ECode  CameraDriver::CamDrv_StopVideoRecord()
{
    if(VIDEO_MODE == m_Format.m_imode){
       return m_pVideo->Stop();
    }
    return E_ACCESS_DENIED;
}

ECode  CameraDriver::CamDrv_GetVideoFrame(Camera_ImageFrame* pFrame)
{
    if(VIDEO_MODE == m_Format.m_imode){
       return m_pVideo->GetFrame(pFrame);
    }
    return E_ACCESS_DENIED;
}

//todo: may add lock
